# CurrentThreadTransactionalConnectionProvider.java

    package org.codefilarete.stalactite.engine;

    import javax.sql.DataSource;
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.sql.Savepoint;
    import java.util.Set;

    import org.codefilarete.stalactite.sql.CommitListener;
    import org.codefilarete.stalactite.sql.ConnectionConfiguration;
    import org.codefilarete.stalactite.sql.CurrentThreadConnectionProvider;
    import org.codefilarete.stalactite.sql.RollbackListener;
    import org.codefilarete.stalactite.sql.TransactionAwareConnexionWrapper;
    import org.codefilarete.tool.collection.KeepOrderSet;
    import org.codefilarete.tool.exception.Exceptions;

    /**
     * {@link org.codefilarete.stalactite.sql.ConnectionProvider} made to match expected contract of {@link PersistenceContext} connection configuration.
     * This implementation uses {@link ThreadLocal} to store and provide connections.
     *
     * @author Guillaume Mary
     */
    public class CurrentThreadTransactionalConnectionProvider implements ConnectionConfiguration.TransactionalConnectionProvider {

    	private final CurrentThreadConnectionProvider jdbcConnectionProvider;

    	private final Set<CommitListener> commitListeners = new KeepOrderSet<>();
    	private final Set<RollbackListener> rollbackListeners = new KeepOrderSet<>();

    	public CurrentThreadTransactionalConnectionProvider(DataSource dataSource) {
    		this.jdbcConnectionProvider = new CurrentThreadConnectionProvider(dataSource);
    	}

    	@Override
    	public Connection giveConnection() {
    		return new TransactionAwareConnexionWrapper(this.jdbcConnectionProvider.giveConnection(), commitListeners, rollbackListeners);
    	}

    	/**
    	 * Implementation based on a {@link Savepoint} on current {@link Connection} to execute given operation.
    	 *
    	 * @param jdbcOperation a sql operation that will call {@link #giveConnection()} to execute its statements.
    	 */
    	@Override
    	@SuppressWarnings("resource" /* put for non-closed Connection which is normal here */)
    	public void executeInNewTransaction(JdbcOperation jdbcOperation) {
    		Connection currentConnection = giveConnection();
    		Savepoint savepoint = null;
    		try {
    			savepoint = currentConnection.setSavepoint();
    			jdbcOperation.execute(currentConnection);
    		} catch (Exception e) {
    			if (savepoint != null) {
    				try {
    					currentConnection.rollback(savepoint);
    					throw Exceptions.asRuntimeException(e);
    				} catch (SQLException e1) {
    					throw Exceptions.asRuntimeException(e1);
    				}
    			} else {
    				// else savepoint can't be created, let's throw an exception
    				throw Exceptions.asRuntimeException(e);
    			}
    		}
    		try {
    			currentConnection.commit();
    		} catch (SQLException e) {
    			throw new RuntimeException(e);
    		}
    	}

    	@Override
    	public void addCommitListener(CommitListener commitListener) {
    		this.commitListeners.add(commitListener);
    	}

    	@Override
    	public void addRollbackListener(RollbackListener rollbackListener) {
    		this.rollbackListeners.add(rollbackListener);
    	}
    }